package cn.wen.yaling.xo.service.impl;

import cn.wen.yaling.commons.constant.Constants;
import cn.wen.yaling.commons.constant.RedisConstants;
import cn.wen.yaling.commons.entity.MenuEntity;
import cn.wen.yaling.commons.entity.TypeEntity;
import cn.wen.yaling.commons.enums.TypeStatus;
import cn.wen.yaling.commons.enums.UserStatus;
import cn.wen.yaling.commons.handler.RequestHolder;
import cn.wen.yaling.commons.service.RedisService;
import cn.wen.yaling.commons.utils.*;
import cn.wen.yaling.commons.vo.*;
import cn.wen.yaling.xo.service.MenuService;
import cn.wen.yaling.xo.service.UserCacheService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.wen.yaling.xo.dao.UserDao;
import cn.wen.yaling.commons.entity.UserEntity;
import cn.wen.yaling.xo.service.UserService;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;


@Service("userService")
public class UserServiceImpl extends ServiceImpl<UserDao, UserEntity> implements UserService {

    @Autowired
    private UserDao userDao;

    @Autowired
    private UserCacheService userCacheService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private MenuService menuService;

    @Value("${yaling-blog.default-password}")
    private String DEFAULT_PASSWORD;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<UserEntity> page = this.page(
                new Query<UserEntity>().getPage(params),
                new QueryWrapper<UserEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public UserEntity getUserByAccount(String account) {
        // 需要先判断redis中是否存在该数据
        UserEntity user = userCacheService.getUser(account);
        if (user != null) return user;
        QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("username",account).
                or().
                eq("user_phone",account);
        user = userDao.selectOne(wrapper);
        // 存储到缓存 需要判断是哪个类型来查找  如果是username则是名字  然后是userPhone 是false
        userCacheService.setUser(user,  true);
        return user;
    }

    @Override
    public UserEntity getUserByAccountDB(String account) {
        QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("username",account).
                or().
                eq("user_phone",account);
        UserEntity user = userDao.selectOne(wrapper);
        return user;
    }

    @Override
    public Long getUserCountByStatus(Integer status) {
        QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("user_status", UserStatus.NORMAL.getStatus());
        return userDao.selectCount(wrapper);
    }

    @Override
    public ResultEntity getUserList() {
        List<UserVO> userList;
        // 1、先判断redis缓存中是否能命中缓存
        if (redisService.hasKey(RedisConstants.CACHE_ADMIN_ALL_USER_LIST)) {
            userList = redisUtils.getListCache(RedisConstants.CACHE_ADMIN_ALL_USER_LIST, UserVO.class);
        } else {
            // 2、获取全部激活的问题列表  包括类别
            userList = userDao.selectUserListByKeywordAndStatus("",
                    UserStatus.NORMAL.getStatus());
            // 3、将db中的缓存获取到
            redisUtils.setListCache( RedisConstants.CACHE_ADMIN_ALL_USER_LIST, userList);
        }
        return ResultEntity.ok().put("data", userList);
    }

    @Transactional
    @Override
    public ResultEntity addUser(UserAddVO userVO) {
        UserEntity target = new UserEntity();
        BeanUtils.copyProperties(userVO, target);
        target.setUserId(UUID.randomUUID().toString().replaceAll("-",""));
        target.setCreateTime(new Date());
        target.setUserStatus(UserStatus.NORMAL.getStatus());
        // 设置默认密码
        target.setPassword(StringUtil.md5(DEFAULT_PASSWORD + "yaling"));
        target.setUpdateTime(new Date());
        boolean res = userDao.insert(target) > 0;
        // 添加到角色关系表中 默认分配普通用户权限
        userDao.insertRoleWithUserRelation(target.getUserId(), Arrays.asList(1));
        if (!res) return ResultEntity.error();
        // 删除缓存
        redisUtils.delUserListCache();
        return ResultEntity.ok();
    }

    @Override
    public ResultEntity editUser(UserUpdateVO userVO) {
        UserEntity target = new UserEntity();
        BeanUtils.copyProperties(userVO, target);
        target.setUpdateTime(new Date());
        // 如果是修改密码则需要加密密码
        if (StringUtils.isNotBlank(userVO.getPassword())) {
            target.setPassword(StringUtil.md5(userVO.getPassword() + "yaling"));
        }
        boolean res = userDao.updateById(target) > 0;
        if (!res) return ResultEntity.error();
        // 删除缓存
        redisUtils.delUserListCache();
        return ResultEntity.ok();
    }

    @Override
    public ResultEntity deleteBatchUserByIds(List<Integer> userIds) {
        boolean res = userDao.updateBatchUserByIds(userIds, UserStatus.LOGICALLY_DELETE.getStatus());
        if (!res) return ResultEntity.error();
        // 删除缓存
        redisUtils.delUserListCache();
        return ResultEntity.ok();
    }

    @Override
    public ResultEntity resetUserPassword(String userId) {
        // 重置用户密码  需要获取配置的密码
        UserEntity target = userDao.selectById(userId);
        target.setUpdateTime(new Date());
        // 默认密码为yaling654
        target.setPassword(StringUtil.md5(DEFAULT_PASSWORD + "yaling"));
        boolean res = userDao.updateById(target) > 0;
        if (!res) return ResultEntity.error();
        // 删除缓存
        redisUtils.delUserListCache();
        return ResultEntity.ok();
    }

    @Override
    public ResultEntity searchUserList(String keyword) {
        List<UserVO> userVOS = userDao.selectUserListByKeywordAndStatus(keyword, UserStatus.NORMAL.getStatus());
        return ResultEntity.ok().put("data", userVOS);
    }

    @Override
    public ResultEntity updateUserRoleRelation(UserRoleUpdateVO userVO) {
        // 1.先将数据库中的用户和角色的连接信息删除
        userDao.deleteUserRoleRelation(userVO.getUserId());
        // 2.然后将传入的数据添加
        boolean res = userDao.insertRoleWithUserRelation(userVO.getUserId(), userVO.getRoleIds());
        if (res) return ResultEntity.ok();
        return ResultEntity.error();
    }

    @Override
    public UserEntity getUserByUserName(String account) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", account).or().eq("user_phone", account);
        queryWrapper.eq("user_status", UserStatus.NORMAL.getStatus());
        return userDao.selectOne(queryWrapper);
    }

    @Override
    public boolean checkUserByUserPhone(String userPhone) {
        QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("user_phone", userPhone);
        UserEntity dbUser = userDao.selectOne(wrapper);
        if (dbUser != null) {
            return true;
        }
        return false;
    }

    @Transactional
    @Override
    public void registerByPhone(String userPhone) {
        UserEntity user = new UserEntity();
        String userId = UUID.randomUUID().toString().replaceAll("-", "");
        user.setUserId(userId);
        user.setPassword(StringUtil.md5(DEFAULT_PASSWORD + "yaling"));
        user.setUserPhone(userPhone);
        user.setNickname(userPhone);
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user.setUserStatus(UserStatus.NORMAL.getStatus());
        userDao.insert(user);
        // 赋予用户权限 默认
        userDao.insertRoleWithUserRelationByUserId(userId, 1);
        updateUserLocalInfo(userId);
        // 删除缓存
        redisUtils.delUserListCache();
    }

    @Override
    public void updateUserLocalInfo(String userId) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        UserEntity user = userDao.selectOne(queryWrapper);
        UserEntity target = new UserEntity();
        HttpServletRequest request = RequestHolder.getRequest();
        QueryWrapper<UserEntity> userEntityQueryWrapper = new QueryWrapper<>();
        userEntityQueryWrapper.eq("user_id", userId);
        target.setUserId(userId);
        String ip = IPUtils.getIpAddr(request);
        target.setLastLoginIp(ip);
        target.setLastLoginTime(new Date());
        target.setLoginCount(user.getLoginCount() == null ? 0 : user.getLoginCount() + 1);
        // 从Redis中获取IP来源
        String jsonResult = (String) redisService.get("IP_SOURCE" + Constants.SYMBOL_COLON + ip);
        if (StringUtils.isEmpty(jsonResult)) {
            String addresses = IPUtils.getAddresses("IP" + "=" + ip, "UTF-8");
            if (StringUtils.isNotEmpty(addresses)) {
                target.setIpSource(addresses);
                redisService.setEx("IP_SOURCE" + Constants.SYMBOL_COLON + ip, addresses, 24, TimeUnit.HOURS);
            }
        } else {
            target.setIpSource(jsonResult);
        }
        userDao.update(target, userEntityQueryWrapper);
    }

    @Transactional
    @Override
    public void registerByUser(RegisterUser userVO) {
        UserEntity user = new UserEntity();
        String userId = UUID.randomUUID().toString().replaceAll("-", "");
        user.setUserId(userId);
        user.setPassword(StringUtil.md5(userVO.getPassword() + "yaling"));
        user.setUserPhone(userVO.getPhone());
        user.setNickname(userVO.getPhone());
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user.setUserStatus(UserStatus.NORMAL.getStatus());
        userDao.insert(user);
        // 赋予用户权限 默认
        userDao.insertRoleWithUserRelationByUserId(userId, 1);
        updateUserLocalInfo(userId);
        // 删除缓存
        redisUtils.delUserListCache();
    }

    @Override
    public ResultEntity getUserInfoByUserId(String userId) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("user_status", UserStatus.NORMAL.getStatus());
        UserEntity userEntity = userDao.selectOne(queryWrapper);
        return ResultEntity.ok().put("data", userEntity);
    }

    @Override
    public UserEntity getUserByUserId(String userId) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        queryWrapper.eq("user_status", UserStatus.NORMAL.getStatus());
        return userDao.selectOne(queryWrapper);
    }

    @Override
    public ResultEntity getUserMenuList(String userId) {
        // 判断是否存在当前用户
        boolean isUser = checkUserByUserId(userId);
        if (!isUser) return ResultEntity.error("该用户不存在！");
        // 获取该用户角色
        int roleId = userDao.getRoleByUserId(userId);
        // 获取菜单列表
        List<MenuVO> list = menuService.getMenuListByRoleId(roleId);
        return ResultEntity.ok().put("data", list);
    }

    public boolean checkUserByUserId(String userId) {
        QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        UserEntity res = userDao.selectOne(queryWrapper);
        return res != null;
    }


}